package com.ccl.iot.publics;import java.util.ArrayList;

import android.os.Handler;
import android.os.Message;
import android.util.SparseArray;

public class MainThreadHandler {
	private static final boolean KDEBUG = false;
	
	public interface MessageListener{
		public void onNewMessage(Message aMessage);
	}
	
	public static boolean IsMainThread(){
		return Thread.currentThread().getName().equalsIgnoreCase("main");
	}

	public static MainThreadHandler newInstance(MessageListener aListener){
		if (IsMainThread()){
			return new MainThreadHandler(aListener);
		}
		
		return null;
	}
	
	
	private MessageListener iListener = null;
	
	private SparseArray<int[]> iMutex = null;
	private ArrayList<Message> iSequence = null;
	
	private Thread iThread = null;
	private boolean iThreadSelfLocked = false;
	
	private MainThreadHandler(MessageListener aListener){
		iListener = aListener;
	}
	
	public void cleanup(){
		if (iThread != null){
			if (iThread.isInterrupted() == false){
				iThread.interrupt();
			}
			
			iThread = null;
		}
	}
	
	private Handler iHandler = new Handler(){
		@Override
		public void handleMessage(Message msg) {		
			if (iThread != null){
				MainThreadHandler.this.handleMessage(msg);
				
				synchronized(iThread){
					if (KDEBUG){
						Debugger.Print("(Notify in main thread)" + iThread.getName());
					}
					
					iThread.notify();
				}
			}			
		}
	};
	
	public void setMessageMutex(int aMessageID, int ...aMutex){
		if (aMutex != null && aMutex.length > 0){
			if (iMutex == null){
				iMutex = new SparseArray<int[]>();
			}
			
			iMutex.put(aMessageID, aMutex);
		}
	}
	
	public void newMessage(int aMessageID, Object aObject){
		newMessage(Message.obtain(iHandler, aMessageID, aObject));
	}
	
	public void newMessage(Message aMessage){
		if (aMessage != null){
			if (iSequence == null){
				iSequence = new ArrayList<Message>();
			}
			
			if (iSequence.add(aMessage)){
				if (KDEBUG){
					Debugger.Print("New message(" + aMessage.what + ") add to sequence, count = " + iSequence.size());
				}
				
				if (iThread == null){
					iThread = new Thread(new Runnable(){
						@Override
						public void run() {
							Thread.currentThread().setName("Main thread message handle thread");
							
							while(iThread != null && iThread.isInterrupted() == false){
								boolean tNeedWait = true;
								
								if (iSequence != null && iSequence.size() > 0){
									Message tMsg = iSequence.get(0);
									
									iSequence.remove(0);
									
									tNeedWait = handleMessage(tMsg);
									
									if (KDEBUG){
										Debugger.Print("Message handled sequence left " + iSequence.size());
									}
								}else{
									iThreadSelfLocked = true;
								}
								
								if (tNeedWait){
									try{
										synchronized(iThread){
											if (KDEBUG){
												Debugger.Print("(Waitting)" + iThread.getName());
											}
	
											iThread.wait();
										}
									}catch (Exception e){
										break;
									}
								}
							}				
							
							iThread = null;
						}				
					});
					
					iThread.start();
				}else{
					if (iThreadSelfLocked){
						synchronized(iThread){
							iThreadSelfLocked = false;
							
							if (KDEBUG){
								Debugger.Print("(Notify in add)" + iThread.getName());
							}
							
							iThread.notify();
						}
					}
				}
			}
		}
	}

	private boolean handleMessage(Message aMessage){
		if (aMessage != null){
			if (iMutex != null){
				int tMutex[] = iMutex.get(aMessage.what);
				
				if (tMutex != null){
					if (messageInSequence(tMutex)){
						if (KDEBUG){
							Debugger.Print("Message(" + aMessage.what + ") ingore by mutex");
						}
						
						return false;
					}
				}
			}
			
			if (IsMainThread()){
				if (KDEBUG){
					Debugger.Print("Message(" + aMessage.what + ") sending to listener");
				}

				if (iListener != null){
					iListener.onNewMessage(aMessage);
				}
			}else{
				if (KDEBUG){
					Debugger.Print("Message(" + aMessage.what + ") sending to handler");
				}
				
				iHandler.sendMessageDelayed(aMessage, 1);
			}
		}
		
		return true;
	}
	
	public boolean messageInSequence(int ...aMessageID){
		if (iSequence != null && aMessageID != null && aMessageID.length > 0){
			for (int i = 0, tCount = iSequence.size(); i < tCount; i++){
				for (int j = 0; j < aMessageID.length; j++){
					if (iSequence.get(i).what == aMessageID[j]){
						return true;
					}
				}
			}
		}
		
		return false;
	}
	
	public void cleanMessage(){
		if (iSequence != null && iSequence.isEmpty() == false){
			iSequence.clear();
		}
	}
}
